""""
设备故障预测程序
在一套对象存储集群中，运维同学希望根据设备运行日志，提前判断设备是否有故障风险，从而把数据在故障前迁移到其他节点。每条日志包含以下字段：设备ID、写入次数、读取次数、平均写入延迟(ms)、平均读取延迟(ms)、使用年限(年)、设备状态(0 正常/1 故障)。

请你实现一个设备故障预测程序，基于训练数据学习一个逻辑回归模型，并对给定的待预测设备输出是否故障的判定结果。


数据清洗规则
- 缺失值填充：数值字段出现字符串 NaN 时，用该字段在训练集中“有效数值”的均值进行填充。有效数值的含义见“异常值处理”。

- 异常值处理：若出现以下越界值，则视为异常，用该字段在训练集“有效数值”的中位数替换。
   1.写入/读取次数：小于 0
   2.平均写入/读取延迟：小于 0 或 大于 1000
   3.使用年限：小于 0 或 大于 20

- 说明：计算均值/中位数时，只统计训练集中“有效数值”（即不含 NaN，且不越界）。若某字段在训练集没有任何有效数值，则该字段的均值与中位数都按 0 处理。
- 标签缺失：训练样本若无状态字段或无法解析为 0/1，丢弃该行，不参与训练，也不参与统计均值/中位数。

模型与训练
- 模型：二分类逻辑回归，带偏置项 w0。
- 训练方法：批量梯度下降（Batch GD），每次迭代用全部训练样本，学习率 0.01，迭代 100 次，初始权重全 0。
- 概率：
  P(y=1) =
1
1
+
e
−
z
1+e 
−z
 
1
​
    其中 z = w0 + 
∑
i
=
1
5
w
i
x
i
∑ 
i=1
5
​
 w 
i
​
 x 
i
​
 

- 判定阈值：若 P(y=1) ≥ 0.5 则输出 1，否则输出 0。
时间限制：C/C++ 1秒，其他语言2秒
空间限制：C/C++ 256M，其他语言512M
输入描述：
第一行：N（2 ≤ N ≤ 100）
接下来 N 行：每行一个训练样本
device_id,writes,reads,avg_write_ms,avg_read_ms,years,status
第 N+1 行：M（1 ≤ M ≤ 10）
接下来 M 行：每行一个待预测样本（无状态）
  device_id,writes,reads,avg_write_ms,avg_read_ms,years
输出描述：
共 M 行，每行输出一个整数 0 或 1，对应各待预测设备是否判定为故障。

"""

import sys,math

def parse_line(line):
    parts=[ p.strip() for p in line.strip().split(",")]
    if not parts:
        return None
    id_=parts[0]
    if len(parts)<7:
        return None

    feats_raw=parts[1:6]
    y_raw=parts[-1]
    def to_num(s):
        if s=="NaN":
            return None

        try:
            return float(s)
        except:
            return None
    
    x=[to_num(v) for v in feats_raw]

    y=0
    try:
        y=int(float(y_raw))
    except:
        y=0
    return id_,x,y

def valid(col,v):
    if v is None:
        return False
    if col in (0,1):
        return v>=0
    if col in (2,3):
        return 0<=v<=1000
    if col==4:
        return 0<=v<=20
    return True

def median(vals):
    n=len(vals)
    if n==0:
        return 0.0
    vals2=sorted(vals)
    mid=n//2
    if n%2==1:
        return vals2[mid]
    else:
        return 0.5*(vals2[mid-1]+vals2[mid])

def sigmoid(z):
    if z>30:
        z=30
    if z<-30:
        z=-30
    return 1.0/(1.0+math.exp(-z))

def clean_matrix(X,means,meds):
    n=len(X)
    d=len(X[0]) if n else 5
    out=[]

    for i in range(n):
        row=[]
        for j in range(d):
            v=X[i][j]
            if v is None:
                v=means[j]
            if not valid (j,v):
                v=meds[j]
            row.append(v)
        out.append(row)
    return out

def main():
    data=sys.stdin.read().strip().splitlines()
    if not data:
        return 
    it=0

    while it<len(data) and data[it].strip()=="":
        it+=1
    N=int(data[it].strip());it+=1

    trainX_raw,trainY=[],[]
    for _ in range(N):
        while it<len(data) and data[it].strip()=="":
            it+=1
        id_x,x,y=parse_line(data[it])
        it+=1
        trainX_raw.append(x)
        trainY.append(y)

    d=5
    means=[0.0]*d
    for j in range(d):
        col=[row[j] for row in trainX_raw if row[j] is not None]
        means[j]=(sum(col)/len(col) if col else 0.0)


    meds=[0.0]*d
    for j in range(d):
        col_valid=[row[j] for row in trainX_raw if valid(j,row[j])]

        if not col_valid:
            meds[j]=means[j]
        else:
            meds[j]=median(col_valid)

    trainX=clean_matrix(trainX_raw,means,meds)

    while it<len(data) and data[it].strip()=="":
        it+=1
    M=int (data[it].strip())
    it+=1

    #测试集
    testX_raw=[]

    for _ in range(M):
        while it<len(data) and data[it].strip()=="":
            it+=1
        parts=[ p.strip() for p in data[it].strip().split(",")]
        it+=1

        feats_raw=parts[1:6]

        def to_num(s):
            if s=="NaN":
                return None

            try:
                return float(s)
            except:
                return None
        testX_raw.append([to_num(v) for v in feats_raw])

    testX=clean_matrix(testX_raw,means,meds)

    n=len(trainX)
    w=[0.0]*(d+1)

    alapha=0.01
    T=100

    for _ in range(T):
        g=[0.0]*(d+1)

        for i in range(n):
            z=w[0]
            for j in range(d):
                z+=w[j+1]*trainX[i][j]
            p=sigmoid(z)

            diff=p-trainY[i]
            g[0]+=diff

            for j in range(d):
                g[j+1]+=diff*trainX[i][j]

        for k in range(d+1):
            w[k]-=alapha*g[k]/n

    #预测

    out_lines=[]

    for i in range(M):
        z=w[0]
        for  j in range(d):
            z+=w[j+1]*testX[i][j]
        p=sigmoid(z)
        pred= 1 if p >=0.5 else 0

        out_lines.append(str(pred))
    print("\n".join(out_lines))

main()



    

"""
12
n1,50,25,5,2,1,0
n2,55,27,5.5,2.5,1.2,0
n3,60,30,6,3,1.5,0
n4,65,32,6.5,3.2,1.8,0
n5,70,35,7,3.5,2,0
n6,75,37,7.5,3.8,2.2,0
n7,80,40,8,4,2.5,0
n8,85,42,8.5,4.2,2.7,0
n9,90,45,9,4.5,3,0
n10,95,47,9.5,4.8,3.2,0
p1,400,200,20,10,6,1
p2,500,250,22,11,8,1
2
q1,88,44,8.8,4.3,2.9
q2,480,240,21.5,10.8,7.5

预期输出
0
1

注意：如果碰到还在等待输入的情况下，可以用ctrl+z退出， 还是能够得到结果的。
"""




